Executing processes on a computer system may comprise all or a portion of operating systems, application programs, device drivers, etc. Processor executable instructions, e.g., which comprise executing processes, may be provided in the form of one or more threads for execution by the processor.
A process is a container for a set of instructions that carry out all or a portion of the overall task of a program. Processes comprise executing application programs, managed by operating system components such as a scheduler and a memory management program and/or a portion of the operating system. A process context comprises the executable instructions, data (used by the executable instructions), and stack (memory used when the process is running). A process is a representation of an executing program and a thread is a fraction of the program. A thread is a sequence of executing instructions of a program. Certain threads exist within the context of a process and provide a means to address and execute smaller segments of the process. Threads allow programs to be broken up into logically distinct tasks. Each thread can be scheduled, synchronized, and prioritized with respect to one or more threads.
When a thread becomes ready for execution by a processor it is said to be a “runnable” thread. The thread may execute after acquiring a lock for synchronization, e.g., a synchronization object. When a thread acquires the synchronization lock, the processor selects and executes the thread.
Programmers use software locks (hereafter referred to as locks or synchronization objects) in order to synchronize multiple threads of execution needing to access or modify shared or otherwise interdependent data. In complex multithreaded software, multiple locks are acquired and held simultaneously during execution of a thread.
Multiple threads which are made runnable at one time may contend for a synchronization object. When this happens, contention on synchronization objects protecting the state of the threads can become high. In addition, starvation of threads can occur as some threads may not obtain the synchronization object which the threads are awakened to obtain.
In some approaches, a single thread is awakened on each synchronization object release resulting in the possibility that multiple threads may end up “in flight”, i.e., starting to wake up prior to attempting to obtain the synchronization object, for synchronization objects with short hold times (i.e., the amount of time the thread holds onto the synchronization object) because the first thread awake may be in the process of being runnable while a subsequent thread obtains the synchronization object.
The subsequent thread may then release the synchronization object causing the awakening of the next sleeping thread waiting on the synchronization object. At this point, two threads are “in-flight” at once attempting to awaken in order to obtain the synchronization object. Multiple threads in flight may cause contention on internal synchronization objects used to maintain thread state. The contention may cause an overall slowdown in synchronization object throughput and consume excessive amounts of processing resources.
Multiple threads contending for a synchronization object may also result in starvation of threads waiting for the synchronization object to execute. For example, if a thread is unable to obtain the synchronization object each time the thread requests the synchronization object, the thread may continuously attempt to obtain the synchronization object.